package com.dayday.edu.factory;

import com.dayday.edu.annotation.Autowired;
import com.dayday.edu.annotation.Service;
import com.dayday.edu.annotation.Transactional;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author dayday
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    private static final Map<String,Object> map = new HashMap<>();  // 存储对象
    private static final List<String> list = new ArrayList<>(); // 存储com.dayday.edu下所有包的路径

    private static final String basePath = "/Users/dayday/Downloads/spring/代码/dayday-transfer/src/main/java/";

    static {
        String scanPath = "com/dayday/edu";
        String path = basePath + scanPath;
        dfs(new File(path));
        // 解析所有的service类
        for (String s : list) {
            try {
                Class<?> aClass = Class.forName(s);
                if (aClass.isAnnotationPresent(Service.class)) {
                    Service annotation = aClass.getAnnotation(Service.class);
                    if (annotation.value().equals("")) {
                        map.put(aClass.getName(), aClass.getDeclaredConstructor().newInstance());
                    } else {
                        map.put(annotation.value(), aClass.getDeclaredConstructor().newInstance());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 解析service类需要注入的对象
        for (Map.Entry<String, Object> service : map.entrySet()) {
            Object o = service.getValue();
            Class<?> aClass = o.getClass();
            //拿到所有字段
            Field[] declaredFields1 = aClass.getDeclaredFields();
            for (Field declaredField : declaredFields1) {
                // 判断字段上是否有Autowired注解
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    // 拿到所有方法
                    Method[] declaredMethods = aClass.getDeclaredMethods();
                    for (Method declaredMethod : declaredMethods) {
                        String[] split = declaredField.getType().getName().split("\\.");
                        // 如果方法名称和set+字段名称一致就用setX方法注入进去
                        if (declaredMethod.getName().equals("set" + split[split.length - 1])) {
                            try {
                                declaredMethod.invoke(o, map.get(split[split.length - 1]));
                            } catch (IllegalAccessException | InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }

            // 判断是否有方法携带了Transactional注解
            if (aClass.isAnnotationPresent(Transactional.class)) {
                ProxyFactory proxyFactory = (ProxyFactory )BeanFactory.getBean("proxyFactory");
                Class<?>[] interfaces = aClass.getInterfaces();
                // 实现了接口就用jdk动态代理 没实现接口就用cglib动态代理
                if (interfaces.length > 0) {
                    o =  proxyFactory.getJdkProxy(o);
                } else  {
                    o = proxyFactory.getCglibProxy(o);
                }
            }
            map.put(service.getKey(), o);
        }

    }

    /**
     * 递归遍历目录下所有的Java文件
     * @param dir
     */
    public static void dfs(File dir) {
        if (dir == null || !dir.exists()) {
            return;
        }
        if (dir.isFile()) {
            if (!dir.getName().contains(".java")) {
                return;
            }
            list.add(dir.getAbsolutePath().replace(basePath, "").replace(".java", "").
                    replace("/", "."));
            System.out.println(dir.getName());
            return;
        }
        for (File file : Objects.requireNonNull(dir.listFiles())) {
            dfs(file);
        }
    }

    /**
     * 获取对象对外接口
     * @param id
     * @return
     */
    public static  Object getBean(String id) {
        return map.get(id);
    }

}
